import lombok.Singular;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.ArrayList;
import java.util.Base64;

/**
 * <p>
 * SHA-256加密
 * </p>
 *
 * @author KANLEI
 * @email freefree.me@qq.com
 * @create 2020-10-28
 */
@Slf4j
public class StringUtils {
    // SHA—256加密数据
    public static String applySHA256(String input) {

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] hash = messageDigest.digest(input.getBytes(StandardCharsets.UTF_8));
            BigInteger temp = new BigInteger(1, hash);
            return temp.toString(16);
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage());
            return null;
        }
    }
    // 私钥生成签名数据
    public static byte[] applyECDSASig(PrivateKey key, String input) {

        try {
            Signature signature;
            // 使用指定provider提供的算法获取signature对象
            signature = Signature.getInstance("ECDSA","BC");

            signature.initSign(key);
            byte[] inputBytes = input.getBytes();
            // Updates the data to be signed or verified, using the specified array of bytes
            signature.update(inputBytes);

            return signature.sign();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
    // 公钥和签名数据校验签名
    public static boolean verifyECDSASig(PublicKey key, String data, byte[] signature) {
        try {
            Signature verifySig = Signature.getInstance("ECDSA", "BC");
            verifySig.initVerify(key);
            verifySig.update(data.getBytes());
            return verifySig.verify(signature);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    // 密钥生成string
    public static String getStringFromKey(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    public static String getMerkleRoot(ArrayList<Transaction> transactions) {
        int count = transactions.size();
        ArrayList<String> previousTreeLayer = new ArrayList<>();
        for (Transaction transaction : transactions) {
            previousTreeLayer.add(transaction.transactionId);
        }
        ArrayList<String> treeLayer = previousTreeLayer;
        while (count > 1) {
            treeLayer = new ArrayList<>();
            for (int i = 1; i < previousTreeLayer.size(); i++) {
                treeLayer.add(applySHA256(previousTreeLayer.get(i - 1) + previousTreeLayer.get(i)));
            }
            count = treeLayer.size();
            previousTreeLayer = treeLayer;
        }
        return treeLayer.size() == 1 ? treeLayer.get(0) : "";
    }

}
